package itdep.common.i18n;

import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Locale;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author Ivan Khalopik
 * @version $Revision: 4 $ $Date: 2010-06-10 13:13:16 +0000 (Thu, 10 Jun 2010) $
 */
public class DynamicNamingStrategy extends ResolvableNamingStrategy {
	private static final String DEFAULT_SOURCE_NAME = "dynamic";
	private static final String VARIABLE_PREFIX = "\\{";
	private static final String VARIABLE_POSTFIX = "\\}";
	private static final Pattern VARIABLE_PATTERN = Pattern.compile(".*" + VARIABLE_PREFIX + "(\\S+)" + VARIABLE_POSTFIX + ".*");
	private static final String GETER_PREFIX = "get";
	private static final String THIS_VARIABLE = "this";
	private static final String DEFAULT_PATTERN = VARIABLE_PREFIX + THIS_VARIABLE + VARIABLE_POSTFIX;

	public DynamicNamingStrategy() {
		super(DEFAULT_SOURCE_NAME);
	}

	protected DynamicNamingStrategy(final String sourceName) {
		super(sourceName);
	}

	public String getName(final Locale locale, final Object value, final Object... parameters) {
		final String pattern = (parameters != null && parameters.length > 0 && parameters[0] != null) ?
				String.valueOf(parameters[0]) : getDefaultPattern();
		return getName(locale, value, pattern);
	}

	@SuppressWarnings({"UnusedDeclaration"})
	protected String getName(final Locale locale, final Object value, final String pattern) {
		String result = pattern;
		Matcher matcher = VARIABLE_PATTERN.matcher(pattern);
		while (matcher.matches()) {
			result = result.replaceAll(VARIABLE_PREFIX + matcher.group(1) + VARIABLE_POSTFIX, String.valueOf(resolveVariable(locale, value, matcher.group(1))));
			matcher = VARIABLE_PATTERN.matcher(result);
		}
		return result;
	}

	protected Object resolveVariable(final Locale locale, final Object bean, final String variable) {
		Object addVariable = null;
		if (bean != null) {
			final StringTokenizer tok = new StringTokenizer(variable);
			final String firstPart = tok.nextToken(".");
			if ("i18n".equals(firstPart)) {
				addVariable = resolveAdditionalVariable(locale, bean, variable);
			} else {
				final Method method = ReflectionUtils.findMethod(bean.getClass(), GETER_PREFIX + StringUtils.capitalize(firstPart));
				if (method != null) {
					Object beanNew;
					try {
						beanNew = method.invoke(bean);
						if (!tok.hasMoreTokens()) {
							addVariable = beanNew;
						} else {
							String var = tok.nextToken(";");
							addVariable = resolveVariable(locale, beanNew, var.substring(1, var.length()));
						}
					} catch (IllegalAccessException e) {
						e.printStackTrace();  //todo: default catch statement body
					} catch (InvocationTargetException e) {
						e.printStackTrace();  //todo: default catch statement body
					}
				}
			}
		}
		return addVariable;
	}

	protected Object resolveAdditionalVariable(final Locale locale, final Object bean, final String variable) {
		if (THIS_VARIABLE.equals(variable)) {
			return bean;
		}
		if (bean instanceof Map) {
			return ((Map) bean).get(variable);
		}
		return null;
	}

	protected String getDefaultPattern() {
		return DEFAULT_PATTERN;
	}
}